package com.nancal.activiti.service.process;

import com.alibaba.fastjson.JSON;
import com.nancal.activiti.service.FileManageService;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.*;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Attachment;
import org.activiti.engine.task.Task;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.*;

/**
 * 运行中的流程Service
 */
@Slf4j
@Service
@Transactional
public class ProcessRuntimeService {

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private ProcessTaskService processTaskService;

    @Autowired
    private IdentityService identityService;

    @Autowired
    private TaskService taskService;
    @Autowired
    private RepositoryService repositoryService;

    /**
     * 根据流程定义key启动流程实例
     *
     * @param definitionKey
     * @return
     */
    public ProcessInstance startProcessInstanceByKey(String definitionKey, String username) {
        //设置该流程的发起人
        Authentication.setAuthenticatedUserId(username);
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(definitionKey);
        //在历史评论添加信息
        Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();

        taskService.addComment(task.getId(), task.getProcessInstanceId(), username + "提交了申请表单");
        return processInstance;
    }

    /**
     * 通过流程定义id启动流程
     *
     * @param deploymentId
     * @return
     */
    public Map<String, String> startProcessInstanceByDefId(String deploymentId, String username) {

        ProcessDefinition processDefinition1 = repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId).singleResult();
        String processDefinitionId = processDefinition1.getId();
//        ProcessInstance processInstance1 = runtimeService.createProcessInstanceQuery().processDefinitionId(processDefinition1.getId()).singleResult();

        //设置该流程的发起人
        identityService.setAuthenticatedUserId(username);
        ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinitionId);
        //在历史评论添加信息
        Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
        //获取流程名称
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionId).singleResult();
        Model model = repositoryService.createModelQuery().deploymentId(processDefinition.getDeploymentId()).singleResult();

        taskService.addComment(task.getId(), task.getProcessInstanceId(), username + "提交了" + model.getName() + "的申请");
        System.out.println(processInstance);
        Map<String, String> out = new HashMap<>();
        out.put("taskId", task.getId());
        out.put("processInstanceId", processInstance.getProcessInstanceId());
        return out;
    }


    /**
     * 通过流程实例id获取流程实例
     *
     * @param processInstanceId
     * @return
     */
    public ProcessInstance getProcessInstance(String processInstanceId) {
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(processInstanceId).singleResult();
        return processInstance;
    }

    /**
     * 获取活动节点信息
     *
     * @param executionId
     * @return
     */
    public List<String> getActiveActivityIds(String executionId) {
        return runtimeService.getActiveActivityIds(executionId);
    }

    /**
     * 获取执行实例信息
     *
     * @param executionId
     * @return
     */
    public ExecutionEntity getExecutionEntityByExecutionId(String executionId) {
        return (ExecutionEntity) runtimeService.createExecutionQuery().executionId(executionId).singleResult();
    }

    /**
     * 通过任务id获取流程实例
     *
     * @param taskId
     * @return
     */
    public ProcessInstance getProcessInstanceByTaskId(String taskId) {
        Task task = processTaskService.getTaskByTaskId(taskId);
        return getProcessInstance(task.getProcessInstanceId());
    }

    /**
     * 获取运行时的流程变量的值
     *
     * @param executionId
     * @param variableName
     * @return
     */
    public Object getVariable(String executionId, String variableName) {
        return runtimeService.getVariable(executionId, variableName);
    }

    /**
     * 根据流程实例id获取相关变量
     *
     * @param executionId
     * @return
     */
    public Map<String, Object> getVariables(String executionId) {
        return runtimeService.getVariables(executionId);
    }

    /**
     * 根据流程实例ID获取执行实例
     * 注意：可能是多个执行实例ID，比如并行任务的情况
     *
     * @param processInstanceId
     * @return
     */
    public List<Execution> getExecutionByPid(String processInstanceId) {
        return runtimeService.createExecutionQuery().processInstanceId(processInstanceId).list();
    }

    /**
     * 根据流程定义的Key获取所有正在运行的执行实例
     *
     * @param processDefinitionKey
     * @return
     */
    public List<Execution> getExecutionEntityByPKey(String processDefinitionKey) {
        return runtimeService.createExecutionQuery().processDefinitionKey(processDefinitionKey)
                .orderByProcessInstanceId().desc().list();
    }

    /**
     * 判断流程是否结束
     * <p>
     * 说明：true:已结束   false:还没结束
     *
     * @param processInstanceId
     * @return
     */
    public boolean processIsEnd(String processInstanceId) {
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(processInstanceId)
                .singleResult();
        if (processInstance == null) {
            return true;
        }
        return false;
    }

    /**
     * 挂起流程
     *
     * @param processInstanceId
     */
    public void suspendProcess(String processInstanceId) {
        runtimeService.suspendProcessInstanceById(processInstanceId);
    }


    /**
     * 删除流程实例
     *
     * @param processInstanceId
     * @param message
     */
    public void deleteProcessInstanceById(String processInstanceId, String message) {
        runtimeService.deleteProcessInstance(processInstanceId, message);//删除流程

        //historyService.deleteHistoricProcessInstance(processInstanceId);//删除历史记录的流程信息
    }

    private static final Logger LOGGER = LoggerFactory.getLogger(ProcessRuntimeService.class);
    @Value("${instanceFile_hostpath}")
    private String fileHostPath;

    public void saveAttachment(MultipartFile file, String taskId, String processInstanceId) {
        String comFileName = file.getOriginalFilename();
        assert comFileName != null;
        String preFileName = comFileName.substring(0, comFileName.lastIndexOf("."));
        String lastFileName = comFileName.substring(comFileName.lastIndexOf("."));
        String fileName = preFileName + processInstanceId + taskId + lastFileName;

        File test = new File(fileHostPath + "/" + fileName);
        if (!test.exists()) {
            test.mkdirs();
        }
        try {
            file.transferTo(test);
        } catch (IOException e) {
            LOGGER.error(file.getOriginalFilename() + "文件上传失败", e);
        }

        Attachment attachment = processTaskService.createAttachment(lastFileName.substring(1), taskId, processInstanceId, fileName, "", fileHostPath);
        processTaskService.saveAttachment(attachment);
    }

    public String getAttachment(String processInstanceId, HttpServletResponse response) {
        List<Attachment> attachmentList = processTaskService.getAttachmentByProcessInstanceId(processInstanceId);
        for (Attachment attachment : attachmentList) {
            String url = attachment.getUrl();
            String fileName = attachment.getName();
            if (Objects.isNull(fileName)) {
                return "文件下载失败，请选择文件要下载的文件";
            }
            File file = new File(url + "/" + fileName);
            if (!file.exists()) {
                return "文件不存在";
            }
            byte[] bytes = new byte[2048];
            BufferedInputStream bufferedInputStream = null;
            OutputStream outputStream = null;
            FileInputStream fileInputStream = null;
            try {
                fileInputStream = new FileInputStream(file);
                bufferedInputStream = new BufferedInputStream(fileInputStream);

                response.setHeader("content-type", "application/octet-stream");
                response.setContentType(MediaType.APPLICATION_OCTET_STREAM.toString());
                String fileName1 = fileName.substring(0,fileName.indexOf(processInstanceId));
                String lastString = fileName.substring(fileName.lastIndexOf("."));
                response.addHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(fileName1+lastString , "UTF-8"));
                outputStream = response.getOutputStream();
                int length;
                while ((length = bufferedInputStream.read(bytes)) != -1) {
                    outputStream.write(bytes, 0, length);
                }
                outputStream.flush();
            } catch (Exception e) {
                LOGGER.error("文件下载失败", e);
            } finally {
                try {
                    if (bufferedInputStream != null) {
                        bufferedInputStream.close();
                    }

                    if (outputStream != null) {
                        outputStream.close();
                    }

                    if (fileInputStream != null) {
                        fileInputStream.close();
                    }
                } catch (IOException e) {
                    LOGGER.error(e.getMessage(), e);
                }
            }
            break;
        }
        return "下载成功";
    }
}
